# model

# responsible for various actions to upload a chosen file to the available cloud-based storage-services
# perform RAID-1

# IMPORTANT:
# Documentation how-to work with blobstorage-objects
# http://code.google.com/intl/de-DE/appengine/docs/python/blobstore/overview.html
# http://code.google.com/intl/de-DE/appengine/docs/python/blobstore/blobinfoclass.html
# http://code.google.com/intl/de-DE/appengine/docs/python/blobstore/blobreaderclass.html#Instance_Methods

from google.appengine.ext import webapp
from google.appengine.ext.webapp import blobstore_handlers

from boto.connection import HTTPRequest
from boto.s3.resumable_download_handler import *
from boto.s3.connection import *
from boto.s3.key import *

from Utilities import *

from controller.BuildStorageInfo import *

from model.octopus.datastore.OctopusCloudDatabaseOpenStack import OctopusCloudDatabaseOpenStack

from google.appengine.ext.db import GqlQuery
from google.appengine.ext.blobstore import BlobInfo

from google.appengine.ext.blobstore.blobstore import BlobReader
from google.appengine.ext.blobstore.blobstore import *

import types
from model.storages.s3.FileUploadHandlerRaidOne import FileUploadHandlerRaidOne
from model.storages.s3.FileUploadHandlerRaidFive import FileUploadHandlerRaidFive


class FileUploadHandler(blobstore_handlers.BlobstoreUploadHandler): 
    def post(self):
        utilities = Utilities()
        
        username = utilities.getUsername()
        
        if username:
            # attribute 'file' is the file-upload-field in the form (class BuildStorageInfo)
            uploadedFiles = self.get_uploads('file')
            
            # get some necessary attributes
            key = self.request.get('key')        
            acl = self.request.get('acl')
            
            raidOne = utilities.getRaidOneText()
            raidFive = utilities.getRaidFiveText()
            
            # get the chosen raid-level from the local database
            raidLevel = utilities.getRaidLevel(username)
            
            # get the credentials
            credentials = utilities.getCredentials(username)
            credentialAmount = credentials.count()
            
            # if the chosen raid-level is RAID-1, than call the raid-one-file-upload-handler
            # cases for this file-upload-handler:
            #    * raidLevel == None and available storages == 1
            #    * raidLevel == 1 and available storages == 1
            #    * raidLevel == 1 and available storages == 2
            #    * raidLevel == 1 and available storages == 3
            #    * raidLevel == None and available storages == 2
            #    * raidLevel == 5 and available storages == 1
            #    * raidLevel == 5 and available storages == 2
            if (raidLevel == raidOne and credentialAmount == 2) or (raidLevel == None and credentialAmount == 2) or (raidLevel == None and credentialAmount == 1) or (raidLevel == raidOne and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 2) or (raidLevel == raidOne and credentialAmount == 3):
                fileUploadHandlerRaidOne = FileUploadHandlerRaidOne()
                fileUploadHandlerRaidOne.get(self, uploadedFiles, key, acl)
            
            # if the chosen raid-level is RAID-5, than call the raid-five-file-upload-handler
            # cases for this file-upload-handler:
            #    * raidLevel == 5 and available storages == 3
            if raidLevel == raidFive and credentialAmount == 3:
                fileUploadHandlerRaidFive = FileUploadHandlerRaidFive()
                fileUploadHandlerRaidFive.get(self, uploadedFiles, key, acl)
            
            # if there is no raid-level chosen yet, than redirect to the configuration-page
            if raidLevel == None:
                self.redirect('/chooseraidlevel')
        else:
            self.redirect('/')
                




























                
'''            
#            successRedirect = self.request.get('success_action_redirect')
#            accessKey = self.request.get('AWSAccessKeyId')
#            policy = self.request.get('policy')
#            signature = self.request.get('signature')
            file = self.request.get('file')
            key = self.request.get('key')        
            acl = self.request.get('acl')
            contentType = self.request.get('content-type')
            
            bucketname = utilities.getBucketname(username)
            
            # get the available credentials and storage-amount
            credentials = utilities.getCredentials(username)
            credentialAmount = credentials.count()
            results = credentials.fetch(100)
            
            if uploadedFiles:
                # TODO: 'NOTE'
                # check if the necessary attributes (key-name, acl, content-type) were set respectively chosen
                # if not, do nothing and print a hint-message for the user
                # if it is, than do the procedure below...
                
                
                # determine the file-size and maybe some other file-dependent information (blobFile-attribute is a blobInfo-object)
                blobFile = uploadedFiles[0]
#                print('blob-file: ', blobFile)
#                print('')

                # get the blob-file-key (necessary to identify the blob-file)
                blobKey = blobFile.key()
#                print('blob-key: ', blobKey)
                
                # get the blob-file-size
                blobSize = blobFile.size
#                print('blob-size: ', blobSize) # Bytes
                
                # get the blob-file-name (the same like the key-name)
                blobName = blobFile.filename
#                print('blob-filename: ', blobName)
                
                # get the blob-file content-type
                blobContentType = blobFile.content_type
#                print('blob-contentType: ', blobContentType)
                
                # get the blob-file time-stamp
                blobTimestamp = blobFile.creation
#                print('blob-timestamp: ', blobTimestamp)
#                print('')
                
                # TODO:
                #    datei stueckenweise auslesen, paritaeten berechnen und nach dem RAID-5 prinzip in die verfuegbaren speicherdienste schreiben
                #    http://code.google.com/intl/de-DE/appengine/docs/python/blobstore/blobreaderclass.html#Instance_Methods
                
                # get the blob-reader for the hole file
                blobReader = BlobReader(blobFile)
#                print('blob-reader: ', blobReader)
#                print('')
                
                # determine the sizes of each file-parts
                index = 2
                remainValue = blobSize % index
                blobSizeOne = blobSize / index
                blobSizeTwo = blobSize - blobSizeOne
#                print('remain-value: ', remainValue)
#                print('blob-size-one: ', blobSizeOne)
#                print('blob-size-two: ', blobSizeTwo)
#                print('')
                
                # get the first blob-reader part
                blobReaderPartOne = BlobReader(blobKey, buffer_size=blobSizeOne)
                
#                print('blob-reader-part-one: ', blobReaderPartOne)
#                print('')
                
                # get the second blob-reader part
                blobReaderPartTwo = BlobReader(blobKey, buffer_size=blobSizeOne, position=blobSizeOne)
#                print('blob-reader-part-two: ', blobReaderPartTwo)
#                print('')
                
                # make the blob-info-object for the first file
                blobFileOne = blobReaderPartOne.blob_info
                blobFileOneSize = blobFileOne.size
                
#                print('blob-file-one: ', blobFileOne)
#                print('blob-file-one-size: ', blobFileOneSize)
#                print('')
                
                
                # make the blob-info-object for the second file
                blobFileTwo = blobReaderPartTwo.blob_info
                blobFileTwoSize = blobFileTwo.size
                
#                print('blob-file-two: ', blobFileTwo)
#                print('blob-file-two-size: ', blobFileTwoSize)
                
                
                
                
                
                
                
                
#                blobReader = blobFile.open()
#                print('blob-reader: ', blobReader)
                
#                blobSizePartOne = blobReader.readline(blobSize/3)
#                blobSizePartOne = BlobReader(blobKey, buffer_size=blobSize/3, position=0)
#                print('blob-size-part-one: ', blobSizePartOne)

                # get the blob-reader-object from the blob-info-file object
#                blobReader = blobstore.BlobReader(blobKey, buffer_size=blobSize)
#                print('blob-reader: ', blobReader)
#                print('')
                
                
                
                # den Teil in dem die Datei zerlegt wird auslagern...!!                
#                if credentialAmount > 1:
#                    if credentialAmount >= 3:
#                        index = credentialAmount - 1
#                    elif credentialAmount == 2:
#                        index = credentialAmount
                
                # the index is necessary to perform the modulo-calculation
                # do the modulo-calculation until the remain is null, then the file has a even size, which can be used for the first part 
#                index = 2
#                remainValue = blobSize % index
#                print('remain-value: ', remainValue)
#
#
#                blobSizeOne = (blobSize / index)
#                print('blob-size-one: ', blobSizeOne)
#                
#
#                # calculate the size for the second part (is mostly smaller than the first part) 
#                blobSizeTwo = blobSize - blobSizeOne
#                print('blob-size-two: ', blobSizeTwo)
#                print('')
#
#                # get the first file-part as a blob-reader-object                
#                blobReaderOne = blobstore.BlobReader(blobKey, buffer_size=blobSizeOne, position=0)
#                blobReaderPartOne = blobReaderOne.read(blobSizeOne)
#                blobReaderPartOneSize = len(blobReaderPartOne)
#                print('blob-reader-one: ', blobReaderOne)
#                print('blob-reader-part-one: ', blobReaderPartOne)
#                print('blob-reader-part-one-size: ', blobReaderPartOneSize)
#                print('')
#                
#                # make a file for the first part
##                blobFilePartOne = StringIO.StringIO(blobReaderPartOne)
#                blobFilePartOne = blobReaderOne.blob_info
#                blobFilePartOneSize = blobFilePartOne.size
#                print('blob-file-part-one: ', blobFilePartOne)
#                print('blob-file-part-one-size: ', blobFilePartOneSize)
#                print('')
#                
#                # get the second file-part as a blob-reader-object
#                blobReaderTwo = blobstore.BlobReader(blobKey, buffer_size=blobSizeTwo, position=blobSizeOne)
#                
#                blobReaderTwo.seek(blobSizeOne)
#                
#                blobReaderPartTwo = blobReaderTwo.read(blobSizeTwo)
#                blobReaderPartTwoSize = len(blobReaderPartTwo)
#                print('blob-reader-two: ', blobReaderTwo)
#                print('blob-reader-part-two: ', blobReaderPartTwo)
#                print('blob-reader-part-two-size: ', blobReaderPartTwoSize)
#                print('')
#                
#                # make a file for the second part
##                blobFilePartTwo = StringIO.StringIO(blobReaderPartTwo)
#                blobFilePartTwo = blobReaderTwo.blob_info
#                blobFilePartTwoSize = blobFilePartTwo.size
#                print('blob-file-part-two: ', blobFilePartTwo)
#                print('blob-file-part-two-size: ', blobFilePartTwoSize)
#                print('')
#                
#                # convert the first blob-reader-file form string into integer
#                blobReaderPartOneInteger = []
#                for i in range(len(blobReaderPartOne)):
#                    blobReaderPartOneInteger.append(ord(blobReaderPartOne[i]))
#                    
#                print('')
#                print('blob-reader-part-one-int: ', blobReaderPartOneInteger)
#                print('blob-reader-part-one-len: ', len(blobReaderPartOneInteger))
#                print('')
#                
#                # convert the second blob-reader-file from string into integer
#                blobReaderPartTwoInteger = []
#                for j in range(len(blobReaderPartTwo)):
#                    blobReaderPartTwoInteger.append(ord(blobReaderPartTwo[j]))
#                
#                print('blob-reader-part-two-int: ', blobReaderPartTwoInteger)    
#                print('blob-reader-part-two-len: ', len(blobReaderPartTwoInteger))
#                print('')
#                
#
#                # if the second file part has less bits than the first one, add the necessary amount to the end..
#                while len(blobReaderPartOneInteger) < len(blobReaderPartTwoInteger):
#                    blobReaderPartOneInteger.append(0)
#                    
#                    print('adjusted blob-reader-part-one-int: ', len(blobReaderPartOneInteger))
#
#                # compute the parity of the two file parts
#                blobReaderParityList = []
#                for k in range(len(blobReaderPartOneInteger)):
#                    blobReaderParityList.append(chr(blobReaderPartOneInteger[k] ^ blobReaderPartTwoInteger[k]))
#                    
#                # convert the parity form integer into string
#                parity = ''
#                for l in range(len(blobReaderParityList)):
#                    parity = parity + str(blobReaderParityList[l]).replace("'\\'", "'\'")
#                    
##                blobReaderParity = blobstore.BlobReader(parity)
##                blobFileParity = blobReaderParity.blob_info
#                    
#                # make a blob-file for the parity
##                blobFileParity = parity.blob_info
#                
#                print('parity: ', parity)
#                print('parity-len: ', len(parity))
##                print('blob-reader-parity: ', blobReaderParity)
##                print('parity-file: ', blobFileParity)
#                print('')
#                
#                               
#                # calculate the md5-checksums for each part (part-one, part-two, part-parity)
##                md5PartOne = utilities.computeMD5ForFile(blobName, blobFilePartOne)
#                md5PartOne = blobFilePartOne.md5_hash
#                print('md5-part-one: ', md5PartOne)
#                
##                md5PartTwo = utilities.computeMD5ForFile(blobName, blobFilePartTwo)
#                md5PartTwo = blobFilePartTwo.md5_hash
#                print('md5-part-two: ', md5PartTwo)
#                
##                md5Parity = utilities.computeMD5ForFile(blobName, parity)
##                md5Parity = blobFileParity.md5_hash
##                print('md5-parity: ', md5Parity)
#                
#                
#                
#                
#                
#                
#                # dateiteil aus paritaet und rest-dateiteil berechnen (TEST)
##                output = []
##                strOutput = ''
##                for m in range(len(blobReaderPartOneInteger)):
##                    output.append(chr(blobReaderPartOneInteger[m] ^ ord(blobReaderParityList[m])))
##                    strOutput = strOutput + chr(blobReaderPartOneInteger[m] ^ ord(blobReaderParityList[m]))
##                    
##                print('output: ', output)
##                print('a: ', strOutput)
##                print('b: ', blobReaderPartTwo)
##                
##                isEqual = cmp(strOutput, blobReaderPartTwo)
##                print('is equal? ', isEqual)
##
##                
##                output2 = []
##                strOutput2 = ''
##                for n in range(len(blobReaderPartTwoInteger)):
##                    output2.append(chr(blobReaderPartTwoInteger[n] ^ ord(blobReaderParityList[n])))
##                    strOutput2 = strOutput2 + chr(blobReaderPartTwoInteger[n] ^ ord(blobReaderParityList[n]))
##                
##                print('c: ', strOutput2)
##                print('d: ', blobReaderPartOne)
##                
##                isEqual2 = cmp(strOutput2, blobReaderPartOne)
##                print('is equal? ', isEqual2)
#                
#                                
#                
#                
#                
#                    
#                
##                # determine the available credentials
##                credentials = utilities.getCredentials(username)
##                credentialsAmount = credentials.count()
##                results = credentials.fetch(100)
                
                if credentials:
                    for result in results:
                        regionname = result.regionname
                        
                        if regionname == utilities.getAmazonText():
                            amazonStorageConnection = utilities.getStorageServiceConnectionByResult(username, result)
#                            self.uploadFile(utilities, regionname, amazonStorageConnection, bucketname, blobFile, key, acl)

                            self.uploadFile(utilities, regionname, amazonStorageConnection, bucketname, blobFileOne, key, acl, blobSizeOne)
                        
                        if regionname == utilities.getGoogleText():
                            googleStorageConnection = utilities.getStorageServiceConnectionByResult(username, result)
                            self.uploadFile(utilities, regionname, googleStorageConnection, bucketname, blobFile, key, acl)
                            
                        if regionname == utilities.getOpenStackText():
                            openStackStorageConnection = utilities.getStorageServiceConnectionByResult(username, result)
#                            self.uploadFile(utilities, regionname, openStackStorageConnection, bucketname, blobFile, key, acl)

                            self.uploadFile(utilities, regionname, openStackStorageConnection, bucketname, blobFileTwo, key, acl, blobSizeTwo)
                            
                else:
                    keyList = self.getKeyList(utilities, username, bucketname)                
                    
#                    hintText = _('An error occurred - could not get the available credentials')
                    hintText = 'An error occurred - could not get the available credentials'
                    hintColor = 'red'
                    
                    self.callBuilder(userText, username, url, urlText, hintText, hintColor, keyList)
    
                # when the upload is done - redirect to the select-data-view
                self.redirect('/selectdata')
            else:
                keyList = self.getKeyList(utilities, username, bucketname)
    
#                hintText = _('No file chosen - please choose a file')
                hintText = 'No file chosen - please choose a file'
                hintColor = 'red'
                
                self.callBuilder(userText, username, url, urlText, hintText, hintColor, keyList)
        else:
            self.redirect('/')

    # handle the file-upload..
    def uploadFile(self, utilities, regionname, storageConnection, bucketname, blobFile, key, acl, size=None):
        utilities.uploadFile(regionname, storageConnection, bucketname, blobFile, key, acl, size)
    
    # loads a list of keys that will be shown in the responsible view (by default: amazon)
    def getKeyList(self, utilities, username, bucketname):
        storageConnection = self.getAmazonStorageConnection(utilities, username)
        
        keyList = utilities.getBucketKeyList(storageConnection, bucketname)
        return keyList
        
    # responsible for the amazon-storage-connection
    def getAmazonStorageConnection(self, utilities, username):
        credentials = utilities.getCredentials(username)
        results = credentials.fetch(100)
        
        if credentials:
            for result in results:
                if result.regionname == utilities.getAmazonText():
                    amazonAccessKey = result.accessKey
                    amazonSecretAccessKey = utilities.decodeSecretAccessKey(username, result.secretAccessKey)
                    amazonEndpointURL = utilities.getAmazonURL()
                    
                    amazonStorageConnection = utilities.getS3Connection(amazonAccessKey, amazonSecretAccessKey, amazonEndpointURL)
                    
                    return amazonStorageConnection
        
    # responsible for the call of the get-method of the BuildStorageInfo-Class
    def callBuilder(self, userText, username, url, urlText, hintText, hintColor, keyList):
        
        templateValues = {
                          'userText': userText,
                          'user': username,
                          'urlText': urlText,
                          'url': url,
                          'urlText': urlText,
                          'hintText': hintText,
                          'hintColor': hintColor
                          }
        
        builder = BuildStorageInfo()
        builder.get(self, templateValues, keyList)

'''            

